﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FifaChamps.API.Data;

namespace FifaChamps.API.Logic
{
    public abstract class PhasePlayer : Player
    {
        public int PhasePlayerID { get; protected set; }
        public int? GoalsFor { get; private set; }
        public int? GoalsAgainst { get; private set; }
        public Player Player { get; protected set; }

        protected PhasePlayer() : base() { }

        protected PhasePlayer(int phaseplayerID)
            : this() //TODO GET PHASE PLAYER
        { }

        protected PhasePlayer(Player player)
            : this(0, player)
        {
        }

        protected PhasePlayer(int phaseplayerID, Player player)
            : this(phaseplayerID, player, default(int?), default(int?))
        {
        }

        protected PhasePlayer(int phaseplayerID, int playerID, int? goalsFor, int? goalsAgainst)
            : this(phaseplayerID, Player.Get_Player(playerID), goalsFor, goalsAgainst)
        { }

        protected PhasePlayer(int phaseplayerID, Player player, int? goalsFor, int? goalsAgainst)
        {
            this.PhasePlayerID = phaseplayerID;
            this.GoalsFor = goalsFor;
            this.GoalsAgainst = goalsAgainst;
            this.Player = player;
        }

        public abstract int Add_PhasePlayer(int phaseID);

        #region Static Methods        

        public static PhasePlayer Factory(int playerID, StageType stagetype, params PhaseParam[] pars)
        {
            if (stagetype == StageType.Knockout)
            {
                return Factory<KnockoutPlayer>(playerID, pars);
            }

            return null;
        }

        public static T Factory<T>(int playerID, params PhaseParam[] pars) where T : PhasePlayer
        {
            return Factory<T>(playerID, default(int?), default(int?), pars);
        }

        public static T Factory<T>(int playerID, int? goalsFor, int? goalsAgainst, params PhaseParam[] pars) where T : PhasePlayer
        {            
            if (typeof(T) == typeof(KnockoutPlayer))
            {
                var player = new KnockoutPlayer(0, playerID, goalsFor, goalsAgainst);
                if (pars != null)
                {
                    if (pars.Where(x => x.Name == "advanced").Any()) player.Advanced = (bool)pars.Where(x => x.Name == "advanced").First().Value;
                }
                return player as T;
            }
            else if (typeof(T) == typeof(GroupPlayer))
            {
                var player = new GroupPlayer(0, playerID, goalsFor, goalsAgainst);
                return player as T;
            }

            return (T)null;
        }

        #endregion
    }

    public class SeasonPlayer : PhasePlayer
    {
        public int? Position { get; private set; }
        public int? Points { get; private set; }
        public int? GamesPlayed { get; private set; }

        public override int Add_PhasePlayer(int phaseID)
        {
            throw new NotImplementedException();
        }
    }

    public class GroupPlayer : PhasePlayer
    {
        public int? Position { get; private set; }
        public int? Points { get; private set; }
        public int? GamesPlayed { get; private set; }

        internal GroupPlayer(int phaseplayerID, int playerID, int? goalsFor, int? goalsAgainst)
            : base(phaseplayerID, Player.Get_Player(playerID), goalsFor, goalsAgainst)
        {
            this.Position = default(int?);
            this.Points = default(int?);
            this.GamesPlayed = default(int?);
        }

        internal GroupPlayer(int phaseplayerID, int playerID, int? goalsFor, int? goalsAgainst, int? position,
            int? points, int? gamesPlayed)
            : base(phaseplayerID, Player.Get_Player(playerID), goalsFor, goalsAgainst)
        {
            this.Position = position;
            this.Points = points;
            this.GamesPlayed = gamesPlayed;
        }

        public override int Add_PhasePlayer(int phaseID)
        {
            return DataManager.Add_GroupPlayer(phaseID, this.Player.ID);
        }

        internal static List<GroupPlayer> Get_GroupPhase_Players(int groupID)
        {
            List<GroupPlayer> players = new List<GroupPlayer>();
            var groupPlayers = DataManager.Get_GroupPlayers(groupID);
            foreach (var group_player in groupPlayers)
            {
                var player = new GroupPlayer(group_player.GroupPlayerID, group_player.PlayerID, group_player.GoalsFor,
                    group_player.GoalsAgainst, group_player.Position, group_player.Points, group_player.GamesPlayed);

                players.Add(player);
            }

            return players;
        }
    }

    public class KnockoutPlayer : PhasePlayer
    {
        public bool? Advanced { get; internal set; }

        #region Constructors
        
        protected KnockoutPlayer(int phaseplayerID, Player player)
            : base(phaseplayerID, player)
        {
            Advanced = default(bool?);
        }

        protected KnockoutPlayer(int phaseplayerID, int playerID, bool? advanced) :
            this(phaseplayerID, Player.Get_Player(playerID))
        {
            this.Advanced = advanced;
        }

        internal KnockoutPlayer(int phaseplayerID, int playerID, int? goalsFor, int? goalsAgainst)
            : base(phaseplayerID, Player.Get_Player(playerID), goalsFor, goalsAgainst)
        {

        }

        internal KnockoutPlayer(int phaseplayerID, int playerID, int? goalsFor, int? goalsAgainst, bool? advanced)
            : this(phaseplayerID, Player.Get_Player(playerID), goalsFor, goalsAgainst, advanced)
        {

        }

        internal KnockoutPlayer(int phaseplayerID, Player player, int? goalsFor, int? goalsAgainst, bool? advanced)
            : base(phaseplayerID, player, goalsFor, goalsAgainst)
        {
            Advanced = advanced;
        }
        #endregion

        public override int Add_PhasePlayer(int phaseID)
        {
            return DataManager.Add_KnockoutPlayer(phaseID, this.Player.ID);
        }

        internal static List<KnockoutPlayer> Get_KnockoutPhase_Players(int knockoutID)
        {
            List<KnockoutPlayer> players = new List<KnockoutPlayer>();
            var knockoutPlayers = DataManager.Get_KnockoutPlayers(knockoutID);
            foreach (var ko_player in knockoutPlayers)
            {
                var ko = new KnockoutPlayer(ko_player.KnockoutPlayerID, ko_player.PlayerID, ko_player.GoalsFor,
                    ko_player.GoalsAgainst, ko_player.Advanced);
                players.Add(ko);
            }

            return players;
        }
    }
}
